﻿using MCUPackage;
using MCUPackage.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace SxPackages.STC32G.Models
{
	[Serializable]
	class IICOptions
	{
		protected STC32GQFP64 mParent = null;

		/// <summary>
		/// IIC类型
		/// </summary>
		[Browsable(false)]
		public IICTypes Type { get; protected set; }
		/// <summary>
		/// 使用的引脚名结合
		/// </summary>
		protected string[] mUsePins { get; set; }

		/// <summary>
		/// 切换引脚
		/// </summary>
		/// <param name="aNew"></param>
		/// <param name="aOld"></param>
		/// <returns>是否切换成功</returns>
		protected bool SwitchPins<T>(T aNew, T aOld)
		{
			string[] newPins = TemplateHelper.GetPins(aNew);
			string[] oldPins = TemplateHelper.GetPins(aOld);
			if (this.Enable)
			{
				if (mParent.PinIsUsedTips(newPins))
				{
					return false;
				}
				SetPins(newPins);
				// 清除占用的功能脚
				mParent.ResetPins(oldPins);
			}

			mUsePins = newPins;
			return true;
		}

		private bool mEnable = false;
		[DisplayName("使能"),
		DefaultValue(false),
		JsonProperty(Order = 100),
		Description("是否使能本IIC功能")]
		public virtual bool Enable
		{
			get => mEnable;
			set
			{
				if (value != mEnable)
				{
					if (value)
					{
						if (mParent.PinIsUsedTips(mUsePins))
						{
							return;
						}
						// 设置引脚用途
						SetPins(mUsePins);
					}
					else
					{
						// 清除占用的功能脚
						mParent.ResetPins(mUsePins);
					}
					mEnable = value;
				}
			}
		}

		private IICPins mPins = IICPins.SDA_P14_SCL_P15;
		[DisplayName("使用引脚"),
		DefaultValue(IICPins.SDA_P14_SCL_P15),
		Description("本IIC所使用的引脚设置")]
		public virtual IICPins Pins
		{
			get => mPins;
			set
			{
				if (value != mPins)
				{
					if (SwitchPins(value, mPins))
					{
						mPins = value;
					}
				}
			}
		}

		private bool mMaster = true;
		[DisplayName("主从模式"),
		DefaultValue(true),
		Description("是否使能主机模式")]
		public virtual bool Master
		{
			get => mMaster;
			set
			{
				if (value != mMaster)
				{
					mMaster = value;
					if (Enable)
					{
						SetPins(mUsePins);
					}
				}
			}
		}

		private int mSpeed = 63;
		[DisplayName("总线频率"),
		DefaultValue(63),
		Description("IIC的频率分频器, 只有在主机模式下才会生效")]
		public virtual int Speed
		{
			get => mSpeed;
			set
			{
				if (value != mSpeed)
				{
					if (value < 0 || value > 63)
					{
						return;
					}
					mSpeed = value;
					double speed = mParent.mSYSTEM.FreqValue / (2 * (value * 2 + 4));
					mParent.UpdateMsg($"IIC总线频率为{speed:F2}KHz");
				}
			}
		}

		[DisplayName("主机自动发送"),
		DefaultValue(false),
		Description("主机模式下是否使能自动发送设置, 使能后MCU会自动发送数据并接收ACK信号")]
		public virtual bool WDTA { get; set; } = false;

		private int mSADR = 0;
		[DisplayName("从机地址"),
		DefaultValue(0),
		Description("从机模式下的设备地址, 取值范围0~127")]
		public virtual int SADR
		{
			get => mSADR;
			set
			{
				if (value != mSADR)
				{
					if (value < 0 || value > 127)
					{
						return;
					}
					mSADR = value;
				}
			}
		}

		[DisplayName("从机地址比较"),
		DefaultValue(true),
		Description("从机模式下是否使能从机设备地址比较功能, 使能则必须匹配从机地址, 否则匹配所有设备地址")]
		public virtual bool SL_MA { get; set; } = true;

		[DisplayName("使能中断"),
		DefaultValue(false),
		Description("是否使能IIC中断")]
		public virtual bool EnableTI { get; set; } = false;

		[DisplayName("中断优先级"),
		Description("中断优先级等级设置"),
		DefaultValue(PriorityTypes.最低级)]
		public virtual PriorityTypes Priority { get; set; } = PriorityTypes.最低级;

		[DisplayName("DMA接收使能"),
		DefaultValue(false),
		Description("是否使能本I2C的DMA接收功能")]
		public virtual bool EnableDMARcv { get; set; } = false;

		private int mRcvLength = 256;
		[DisplayName("DMA接收上限"),
		DefaultValue(256),
		Description("DMA接收数据缓冲区的大小, 取值范围1~65536, 不要超过芯片xdata区域的上限")]
		public virtual int RcvLength
		{
			get => mRcvLength;
			set
			{
				if (value != mRcvLength)
				{
					if (value < 1 || value > 65536)
					{
						return;
					}
					mRcvLength = value;
				}
			}
		}

		[DisplayName("DMA发送使能"),
		DefaultValue(false),
		Description("是否使能本I2C的DMA发送功能")]
		public virtual bool EnableDMASnd { get; set; }

		private int mSndLength = 256;
		[DisplayName("DMA发送上限"),
		DefaultValue(256),
		Description("DMA数据发送缓冲区的大小, 取值范围1~65536, 不要超过芯片xdata区域的上限")]
		public virtual int SndLength
		{
			get => mSndLength;
			set
			{
				if (value != mSndLength)
				{
					if (value < 1 || value > 65536)
					{
						return;
					}
					mSndLength = value;
				}
			}
		}

		[DisplayName("DMA中断优先级"),
		Description("DMA中断优先级等级设置"),
		DefaultValue(PriorityTypes.最低级)]
		public virtual PriorityTypes DMAPriority { get; set; } = PriorityTypes.最低级;

		[DisplayName("总线优先级"),
		Description("DMA数据总线访问优先级等级设置"),
		DefaultValue(PriorityTypes.最低级)]
		public virtual PriorityTypes BusPriority { get; set; } = PriorityTypes.最低级;

		protected virtual void SetPins(string[] aPins)
		{
			if (aPins == null || aPins.Length < 2)
			{
				return;
			}
			var opt = mParent.SetPinPurpose(aPins[0], PinPurpose.IIC_SDA);
			if (opt != null)
			{
				if (this.Master)
				{
					opt.Mode = GPIOMode.Push;
				}
				else
				{
					opt.Mode = GPIOMode.Standard;
					opt.EnableUp = true;
				}
				opt.Level = GPIOLevel.High;
				opt.Speed = GPIOSpeed.Fast;
			}
			opt = mParent.SetPinPurpose(aPins[1], PinPurpose.IIC_SCL);
			if (opt != null)
			{
				opt.Mode = GPIOMode.Standard;
				opt.EnableUp = true;
				opt.Level = GPIOLevel.High;
				opt.Speed = GPIOSpeed.Fast;
			}
		}

		public IICOptions(STC32GQFP64 aParent)
		{
			this.mParent = aParent;
			this.Type = IICTypes.IIC;
			mUsePins = TemplateHelper.GetPins(mPins);
		}

		public override String ToString()
		{
			return string.Empty;
		}

		/// <summary>
		/// 初始化模板
		/// </summary>
		private const string MASTER_TEMPLATE =
@"	attr.I2C_Mode     = I2C_Mode_Master;	//主从选择   I2C_Mode_Master, I2C_Mode_Slave
	attr.I2C_Enable   = ENABLE;			//I2C功能使能,   ENABLE, DISABLE
	attr.I2C_MS_WDTA  = {0};			//主机使能自动发送,  ENABLE, DISABLE
	attr.I2C_Speed    = {1};				//总线速度=Fosc/2/(Speed*2+4),      0~63
	I2C_Init(&attr);
	NVIC_I2C_Init(I2C_Mode_Master, {2}, {3});		//主从模式, I2C_Mode_Master, I2C_Mode_Slave; 中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
	I2C_SW(I2C{4});					//I2C_P14_P15,I2C_P24_P25,I2C_P76_P77,I2C_P33_P32";

		/// <summary>
		/// 从机初始化模板
		/// </summary>
		private const string SLAVE_TEMPLATE =
@"	attr.I2C_Mode     = I2C_Mode_Slave;		//主从选择   I2C_Mode_Master, I2C_Mode_Slave
	attr.I2C_Enable   = ENABLE;				//I2C功能使能,   ENABLE, DISABLE
	attr.I2C_SL_MA    = {0};				//使能从机地址比较功能,   ENABLE, DISABLE
	attr.I2C_SL_ADR   = 0x{1:X2};					//从机设备地址,  0~127  (0x2d<<1 = 0x5a)
	I2C_Init(&attr);
	NVIC_I2C_Init(I2C_Mode_Slave, I2C_ESTAI | I2C_ERXI | I2C_ETXI | I2C_ESTOI, {2});	//主从模式, I2C_Mode_Master, I2C_Mode_Slave; 中断使能, I2C_ESTAI/I2C_ERXI/I2C_ETXI/I2C_ESTOI/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
	I2C_SW(I2C{3});					//I2C_P14_P15,I2C_P24_P25,I2C_P76_P77,I2C_P33_P32";

		/// <summary>
		/// DMA初始化模板
		/// </summary>
		private const string DMA_TEMPLATE =
@"	dma.DMA_TX_Length = (uint16_t){0};	//DMA传输总字节数  	(0~65535) + 1
	dma.DMA_TX_Buffer = (uint16_t){1};	//发送数据存储地址
	dma.DMA_RX_Length = (uint16_t){2};	//DMA传输总字节数  	(0~65535) + 1
	dma.DMA_RX_Buffer = (uint16_t){3};	//接收数据存储地址
	dma.DMA_TX_Enable = {4};		//DMA使能  	ENABLE,DISABLE
	dma.DMA_RX_Enable = {5};		//DMA使能  	ENABLE,DISABLE
	DMA_I2C_Inilize(&dma);	//初始化
	NVIC_DMA_I2CT_Init({4}, {6}, {7});		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0~Priority_3; 总线优先级(低到高) Priority_0~Priority_3
	NVIC_DMA_I2CR_Init({5}, {6}, {7});		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0~Priority_3; 总线优先级(低到高) Priority_0~Priority_3
	DMA_I2CR_CLRFIFO();		//清空 DMA FIFO";

		private const string VAR_RCV_TEMPLATE =
@"#define IIC_RCVDMA_MAX	{0}
uint8_t xdata IIC_RcvDMA_Buffer[IIC_RCVDMA_MAX];";

		private const string VAR_SND_TEMPLATE =
@"#define IIC_SNDDMA_MAX	{0}
uint8_t xdata IIC_SndDMA_Buffer[IIC_SNDDMA_MAX];";

		public Boolean AppendConfig(List<String[]> aLst)
		{
			if (!this.Enable)
			{
				return false;
			}

			string name = "IIC_Config";
			StringBuilder funcSb = new StringBuilder();
			funcSb.Append(TemplateHelper.GetFunctionCommit("SPI模块初始化"));
			funcSb.AppendLine($"PRIVATE void {name}(void)").AppendLine("{");
			funcSb.AppendLine("\tI2C_InitTypeDef attr;");
			if (this.EnableDMARcv || this.EnableDMASnd)
			{
				funcSb.AppendLine("\tDMA_I2C_InitTypeDef dma;");
			}

			Dictionary<string, List<string>> lst = new Dictionary<string, List<string>>();
			StringBuilder varSb = new StringBuilder();

			string pins = string.Empty;
			foreach (var pin in mUsePins)
			{
				var opt = mParent.GetPinOption(pin);
				if (opt != null)
				{
					opt.ToDictionary(lst);
					pins += "_";
					pins += pin.Replace(".", "");
				}
			}
			if (lst.Count > 0)
			{
				funcSb.AppendLine();
				funcSb.Append(GPIOOptions.GetGPIOConfigs(lst));
			}

			funcSb.AppendLine();
			if (this.Master)
			{
				funcSb.AppendFormat(MASTER_TEMPLATE, this.WDTA.ToEnable(), this.Speed,
								this.EnableTI.ToEnable(), this.Priority.ToDescription(), pins);
			}
			else
			{
				funcSb.AppendFormat(SLAVE_TEMPLATE, this.SL_MA.ToEnable(), this.SADR, this.Priority.ToDescription(), pins);
			}
			funcSb.AppendLine();

			if (this.EnableDMARcv || this.EnableDMASnd)
			{
				string rcvName = "NULL", sndName = "NULL";
				string rcvLength = "0", sndLength = "0";
				if (this.EnableDMARcv)
				{
					varSb.AppendFormat(VAR_RCV_TEMPLATE, this.RcvLength).AppendLine();
					rcvName = "IIC_RcvDMA_Buffer";
					rcvLength = "(IIC_RCVDMA_MAX - 1)";
				}
				if (this.EnableDMASnd)
				{
					varSb.AppendFormat(VAR_SND_TEMPLATE, this.SndLength).AppendLine();
					sndName = "IIC_SndDMA_Buffer";
					sndLength = "(IIC_SNDDMA_MAX - 1)";
				}
				funcSb.AppendLine();
				funcSb.AppendFormat(DMA_TEMPLATE, sndLength, sndName, rcvLength, rcvName,
									this.EnableDMASnd.ToEnable(), this.EnableDMARcv.ToEnable(),
									this.DMAPriority.ToDescription(), this.BusPriority.ToDescription());
				funcSb.AppendLine();
			}

			funcSb.AppendLine("}");
			aLst.Add(new string[] { funcSb.ToString(), $"{name}();", varSb.ToString() });
			return true;
		}
	}
}
